home *** CD-ROM | disk | FTP | other *** search
/ Enter Special 3: Graphics & Video / Special_03.iso / Grafika / AutoImager 2.4 / setup_ai.exe / %MAINDIR% / Lib / gs_setpd.ps < prev    next >
Encoding:
Text File  |  2002-11-15  |  24.7 KB  |  770 lines

  1. %    Copyright (C) 1994, 2000 Aladdin Enterprises.  All rights reserved.
  2. % This file is part of AFPL Ghostscript.
  3. % AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
  4. % distributor accepts any responsibility for the consequences of using it, or
  5. % for whether it serves any particular purpose or works at all, unless he or
  6. % she says so in writing.  Refer to the Aladdin Free Public License (the
  7. % "License") for full details.
  8. % Every copy of AFPL Ghostscript must include a copy of the License, normally
  9. % in a plain ASCII text file named PUBLIC.  The License grants you the right
  10. % to copy, modify and redistribute AFPL Ghostscript, but only under certain
  11. % conditions described in the License.  Among other things, the License
  12. % requires that the copyright notice and this notice be preserved on all
  13. % copies.
  14.  
  15. % $Id: gs_setpd.ps,v 1.8 2001/07/30 07:11:38 lpd Exp $
  16. % The current implementation of setpagedevice has the following limitations:
  17. %    - It doesn't attempt to "interact with the user" for Policy = 2.
  18.  
  19. languagelevel 1 .setlanguagelevel
  20. level2dict begin
  21.  
  22. % ---------------- Redefinitions ---------------- %
  23.  
  24. % Redefine .beginpage and .endpage so that they call BeginPage and
  25. % EndPage respectively if appropriate.
  26.  
  27. % We have to guard against the BeginPage procedure not popping its operand.
  28. % This is really stupid, but the Genoa CET does it.
  29. /.beginpage {        % - .beginpage -
  30.   .currentshowpagecount {
  31.     .currentpagedevice pop
  32.     dup null ne { /BeginPage .knownget } { pop false } ifelse {
  33.         % Stack: ... pagecount proc
  34.        count 2 .execn
  35.         % Stack: ... ..???.. oldcount
  36.        count 1 add exch sub { pop } repeat
  37.     } {
  38.       pop
  39.     } ifelse
  40.   } if
  41. } bind odef
  42.  
  43. % Guard similarly against EndPage not popping its operand.
  44. /.endpage {        % <reason> .endpage <print_bool>
  45.   .currentshowpagecount {
  46.     1 index .currentpagedevice pop
  47.     dup null ne { /EndPage .knownget } { pop false } ifelse {
  48.         % Stack: ... reason pagecount reason proc
  49.       count 2 .execn
  50.         % Stack: ... ..???.. print oldcount
  51.       count 2 add exch sub { exch pop } repeat
  52.     } {
  53.       pop pop 2 ne
  54.     } ifelse
  55.   } {
  56.     2 ne
  57.   } ifelse
  58. } bind odef
  59.  
  60. % Define interpreter callouts for handling gstate-saving operators,
  61. % to make sure that they create a page device dictionary for use by
  62. % the corresponding gstate-restoring operator.
  63. % We'd really like to avoid the cost of doing this, but we don't see how.
  64. % The names %gsavepagedevice, %savepagedevice, %gstatepagedevice,
  65. % %copygstatepagedevice, and %currentgstatepagedevice are known to the
  66. % interpreter.
  67.  
  68. (%gsavepagedevice) cvn
  69.  { currentpagedevice pop gsave
  70.  } bind def
  71.  
  72. (%savepagedevice) cvn
  73.  { currentpagedevice pop save
  74.  } bind def
  75.  
  76. (%gstatepagedevice) cvn
  77.  { currentpagedevice pop gstate
  78.  } bind def
  79.  
  80. (%copygstatepagedevice) cvn
  81.  { currentpagedevice pop copy
  82.  } bind def
  83.  
  84. (%currentgstatepagedevice) cvn
  85.  { currentpagedevice pop currentgstate
  86.  } bind def
  87.  
  88. % Define interpreter callouts for handling gstate-restoring operators
  89. % when the current page device needs to be changed.
  90. % The names %grestorepagedevice, %grestoreallpagedevice,
  91. % %restorepagedevice, %restore1pagedevice, and %setgstatepagedevice
  92. % are known to the interpreter.
  93.  
  94. /.installpagedevice
  95.  {    % Since setpagedevice doesn't create new device objects,
  96.     % we must (carefully) reinstall the old parameters in
  97.     % the same device.
  98.    .currentpagedevice pop null currentdevice null .trysetparams
  99.    dup type /booleantype eq
  100.     { pop pop }
  101.     {        % This should never happen!
  102.       DEBUG { (Error in .trysetparams!) = pstack flush } if
  103.       cleartomark pop pop pop
  104.       /.installpagedevice cvx /rangecheck signalerror
  105.     }
  106.    ifelse pop pop
  107.     % A careful reading of the Red Book reveals that an erasepage
  108.     % should occur, but *not* an initgraphics.
  109.    erasepage .beginpage
  110.  } bind def
  111.  
  112. /.uninstallpagedevice
  113.  { 2 .endpage { .currentnumcopies false .outputpage } if
  114.    nulldevice
  115.  } bind def
  116.  
  117. (%grestorepagedevice) cvn
  118.  { .uninstallpagedevice grestore .installpagedevice
  119.  } bind def
  120.  
  121. (%grestoreallpagedevice) cvn
  122.  { .uninstallpagedevice grestore .installpagedevice grestoreall
  123.  } bind def
  124.  
  125. (%restore1pagedevice) cvn
  126.  { .uninstallpagedevice grestore .installpagedevice restore
  127.  } bind def
  128.  
  129. (%restorepagedevice) cvn
  130.  { .uninstallpagedevice restore .installpagedevice
  131.  } bind def
  132.  
  133. (%setgstatepagedevice) cvn
  134.  { .uninstallpagedevice setgstate .installpagedevice
  135.  } bind def
  136.  
  137. % Redefine .currentnumcopies so it consults the NumCopies device parameter.
  138. /.numcopiesdict mark
  139.   /NumCopies dup
  140. .dicttomark readonly def
  141.  
  142. /.currentnumcopies
  143.  { currentdevice //.numcopiesdict .getdeviceparams
  144.    dup type /integertype eq
  145.     { exch pop exch pop }
  146.     { cleartomark #copies }
  147.    ifelse
  148.  } bind odef
  149.  
  150. % Redefine .currentpagedevice and .setpagedevice so they convert between
  151. % null and a fixed empty directionary.
  152. /.nullpagedevice 0 dict readonly def
  153. /.currentpagedevice {
  154.   //.currentpagedevice exch dup null eq { pop //.nullpagedevice } if exch
  155. } bind odef
  156. /.setpagedevice {
  157.   dup //.nullpagedevice eq { pop null } if //.setpagedevice
  158. } bind odef
  159.  
  160. % ---------------- Auxiliary definitions ---------------- %
  161.  
  162. % Define the required attributes of all page devices, and their default values.
  163. % We don't include attributes such as .MediaSize, which all devices
  164. % are guaranteed to supply on their own.
  165. /.defaultpolicies mark
  166.   /PolicyNotFound 1
  167.   /PageSize 0
  168.   /PolicyReport {pop} bind
  169. .dicttomark readonly def
  170. % Note that the values of .requiredattrs are executed, not just fetched.
  171. /.requiredattrs mark
  172.   /PageDeviceName null
  173.   /PageOffset [0 0] readonly
  174. % We define InputAttributes and OutputAttributes with a single
  175. % dummy media type that handles pages of any size.
  176. % Devices that care will override this.
  177.   /InputAttributes {
  178.     mark 0
  179.     % Since sizes match within 5 user units, we need to set the smallest
  180.     % PageSize to 6 units so that [0 0] will fail.
  181.     mark /PageSize [6 dup 16#7ffff dup] .dicttomark
  182.     .dicttomark
  183.   }
  184.   (%MediaSource) 0
  185.   /OutputAttributes {
  186.     mark 0 mark .dicttomark readonly .dicttomark
  187.   }
  188.   (%MediaDestination) 0
  189.   /Install {{.callinstall}} bind
  190.   /BeginPage {{.callbeginpage}} bind
  191.   /EndPage {{.callendpage}} bind
  192.   /Policies .defaultpolicies
  193. .dicttomark readonly def
  194.  
  195. % Define currentpagedevice so it creates the dictionary on demand if needed,
  196. % adding all the required entries defined just above.
  197. % We have to deal specially with entries that the driver may change
  198. % on its own.
  199. /.dynamicppkeys mark
  200.   /.MediaSize dup        % because it changes when PageSize is set
  201.   /PageCount dup
  202. .dicttomark readonly def
  203. /.makecurrentpagedevice {    % - .makecurrentpagedevice <dict>
  204.   currentdevice null .getdeviceparams
  205.     % Make the dictionary large enough to add defaulted entries.
  206.   counttomark 2 idiv .requiredattrs length add dict
  207.   counttomark 2 idiv { dup 4 2 roll put } repeat exch pop
  208.     % Add any missing required attributes.
  209.     % Make a writable and (if possible) local copy of any default
  210.     % dictionaries, to work around a bug in the output of WordPerfect,
  211.     % which assumes that these dictionaries are writable and local.
  212.   .currentglobal exch dup gcheck .setglobal
  213.   .requiredattrs {
  214.     2 index 2 index known {
  215.       pop pop
  216.     } {
  217.       exec 2 index 3 1 roll put
  218.     } ifelse
  219.   } forall exch .setglobal
  220.   dup .setpagedevice
  221. } bind def
  222. /currentpagedevice {
  223.   .currentpagedevice {
  224.     dup length 0 eq {
  225.       pop .makecurrentpagedevice
  226.     } {
  227.         % If any of the dynamic keys have changed,
  228.         % we must update the page device dictionary.
  229.       currentdevice //.dynamicppkeys .getdeviceparams .dicttomark {
  230.         % Stack: current key value
  231.         2 index 2 index .knownget { 1 index ne } { true } ifelse
  232.          { 2 index wcheck not
  233.         {    % This is the first entry being updated.
  234.             % Copy the dictionary to make it writable.
  235.           3 -1 roll dup length dict .copydict
  236.           3 1 roll
  237.         }
  238.            if
  239.            2 index 3 1 roll put
  240.          }
  241.          { pop pop
  242.          }
  243.         ifelse
  244.       } forall
  245.         % If the dictionary was global and is now local, copy
  246.         % any global subsidiary dictionaries to local VM.  This
  247.         % too is to work around the Word Perfect bug (see above).
  248.       dup gcheck not {
  249.     dup {
  250.       dup type /dicttype eq { dup gcheck } { false } ifelse {
  251.         % Copy-on-write, see above.
  252.         2 index wcheck not {
  253.           3 -1 roll dup length dict .copydict
  254.           3 1 roll
  255.         } if
  256.         .copytree 2 index 3 1 roll put
  257.       } {
  258.         pop pop
  259.       } ifelse
  260.     } forall
  261.       } if
  262.         % We would like to do a .setpagedevice so we don't keep
  263.         % re-creating the dictionary.  Unfortunately, the effect
  264.         % of this is that if any dynamic key changes (PageCount
  265.         % in particular), we will do the equivalent of a
  266.         % setpagedevice at the next restore or grestore.
  267.         % Therefore, we make the dictionary read-only, but
  268.         % we don't store it away.  I.e., NOT:
  269.         % dup wcheck { .setpagedevice .currentpagedevice pop } if
  270.       readonly
  271.     } ifelse
  272.   } if
  273. } bind odef
  274.  
  275. % Copy a dictionary recursively.
  276. /.copytree {    % <dict> .copytree <dict'>
  277.   dup length dict exch {
  278.     dup type /dicttype eq { .copytree } if 2 index 3 1 roll put
  279.   } forall
  280. } bind def
  281.  
  282. % The implementation of setpagedevice is quite complex.  Currently,
  283. % everything but the media matching algorithm is implemented here.
  284.  
  285. % By default, we only present the requested changes to the device,
  286. % but there are some parameters that require special merging action.
  287. % Define those parameters here, with the procedures that do the merging.
  288. % The procedures are called as follows:
  289. %    <merged> <key> <new_value> -proc- <merged> <key> <new_value'>
  290. /.mergespecial mark
  291.   /InputAttributes
  292.    { dup null eq
  293.       { pop null
  294.       }
  295.       { 3 copy pop .knownget
  296.      { dup null eq
  297.         { pop dup length dict }
  298.         { dup length 2 index length add dict .copydict }
  299.        ifelse
  300.      }
  301.      { dup length dict
  302.      }
  303.         ifelse .copydict readonly
  304.       }
  305.      ifelse
  306.    } bind
  307.   /OutputAttributes 1 index
  308.   /Policies
  309.     { 3 copy pop .knownget
  310.        { dup length 2 index length add dict .copydict }
  311.        { dup length dict }
  312.       ifelse copy readonly
  313.     } bind
  314. .dicttomark readonly def
  315.  
  316. % Define the keys used in input attribute matching.
  317. /.inputattrkeys [
  318.   /PageSize /MediaColor /MediaWeight /MediaType /InsertSheet
  319.     % The following are documented in Adobe's supplement for v2017.
  320.   /LeadingEdge /MediaClass
  321. ] readonly def
  322. % Define other keys used in media selection.
  323. /.inputselectionkeys [
  324.   /MediaPosition /Orientation
  325. ] readonly def
  326.  
  327. % Define the keys used in output attribute matching.
  328. /.outputattrkeys [
  329.   /OutputType
  330. ] readonly def
  331.  
  332. % Define all the parameters that should always be copied to the merged
  333. % dictionary.
  334. /.copiedkeys [
  335.   /OutputDevice
  336.   .mergespecial { pop } forall
  337.   .inputattrkeys aload pop
  338.   .inputselectionkeys aload pop
  339.   .outputattrkeys aload pop
  340. ] readonly def
  341.  
  342. % Define the parameters that should not be presented to the device.
  343. % The procedures are called as follows:
  344. %    <merged> <key> <value> -proc-
  345. % The procedure leaves all its operands on the stack and returns
  346. % true iff the key/value pair should be presented to .putdeviceparams.
  347. /.presentspecial mark
  348.   .dynamicppkeys { pop false } forall
  349.             % We must ignore an explicit request for .MediaSize,
  350.             % because media matching always handles this.
  351.   /.MediaSize false
  352.   /Name false
  353.   /OutputDevice false
  354.   /PageDeviceName false
  355.   /PageOffset false
  356.   /PageSize false        % obsolete alias for .MediaSize
  357.   /InputAttributes false
  358.   .inputattrkeys
  359.     { dup /PageSize eq
  360.        { pop }
  361.        { { 2 index /InputAttributes .knownget { null eq } { true } ifelse } }
  362.       ifelse
  363.     }
  364.   forall
  365.   .inputselectionkeys { false } forall
  366.   /OutputAttributes false
  367.   .outputattrkeys
  368.     { { 2 index /OutputAttributes .knownget { null eq } { true } ifelse } }
  369.   forall
  370.   /Install false
  371.   /BeginPage false
  372.   /EndPage false
  373.   /Policies false
  374.     % Our extensions:
  375.   /HWColorMap
  376.     {            % HACK: don't transmit the color map, because
  377.             % window systems can change the color map on their own
  378.             % incrementally.  Someday we'll have a better
  379.             % solution for this....
  380.       false
  381.     }
  382.   /ViewerPreProcess false
  383. .dicttomark readonly def
  384.  
  385. % Define access to device defaults.
  386. /.defaultdeviceparams
  387.  { finddevice null .getdeviceparams
  388.  } bind def
  389.  
  390. % Select media (input or output).  The hard work is done in an operator:
  391. %    <pagedict> <attrdict> <policydict> <keys> .matchmedia <key> true
  392. %    <pagedict> <attrdict> <policydict> <keys> .matchmedia false
  393. %    <pagedict> null <policydict> <keys> .matchmedia null true
  394. /.selectmedia        % <orig> <request> <merged> <failed>     <-- retained
  395.             %   <attrdict> <policydict> <attrkeys> <mediakey>
  396.             %   .selectmedia
  397.  { 5 index 5 -2 roll 4 index .matchmedia
  398.         % Stack: orig request merged failed attrkeys mediakey
  399.         %   (key true | false)
  400.     { 4 index 3 1 roll put pop
  401.     }
  402.     {    % Adobe's implementations have a "big hairy heuristic"
  403.     % to choose the set of keys to report as having failed the match.
  404.     % For the moment, we report any keys that are in the request
  405.     % and don't have the same value as in the original dictionary.
  406.       5 index 1 index .knownget
  407.        { 4 index 3 1 roll put }
  408.        { 3 index exch .undef }
  409.       ifelse
  410.        {    % Stack: <orig> <request> <merged> <failed> <attrkey>
  411.      3 index 1 index .knownget
  412.       { 5 index 2 index .knownget { ne } { pop true } ifelse }
  413.       { true }
  414.      ifelse        % Stack: ... <failed> <attrkey> <report>
  415.       { 2 copy /rangecheck put }
  416.      if pop
  417.        }
  418.       forall
  419.     }
  420.    ifelse
  421.  } bind def
  422.  
  423. % Apply Policies to any unprocessed failed requests.
  424. % As we process each request entry, we replace the error name
  425. % in the <failed> dictionary with the policy value,
  426. % and we replace the key in the <merged> dictionary with its prior value
  427. % (or remove it if it had no prior value).
  428. /.policyprocs mark
  429. % These procedures are called with the following on the stack:
  430. %   <orig> <merged> <failed> <Policies> <key> <policy>
  431. % They are expected to consume the top 2 operands.
  432. % NOTE: we currently treat all values other than 0, 1, or 7 (for PageSize)
  433. % the same as 0, i.e., we signal an error.
  434.   0 {        % Set errorinfo and signal a configurationerror.
  435.     pop dup 4 index exch get 2 array astore
  436.     $error /errorinfo 3 -1 roll put
  437.     cleartomark
  438.     /setpagedevice load /configurationerror signalerror
  439.   } bind
  440.   1 {        % Roll back the failed request to its previous status.
  441. DEBUG { (Rolling back.) = pstack flush } if
  442.     3 index 2 index 3 -1 roll put
  443.     4 index 1 index .knownget
  444.      { 4 index 3 1 roll put }
  445.      { 3 index exch .undef }
  446.     ifelse
  447.   } bind
  448.   7 {        % For PageSize only, just impose the request.
  449.     1 index /PageSize eq
  450.      { pop pop 1 index /PageSize 7 put }
  451.      { .policyprocs 0 get exec }
  452.     ifelse
  453.   } bind
  454. .dicttomark readonly def
  455. /.applypolicies        % <orig> <merged> <failed> .applypolicies
  456.             %   <orig> <merged'> <failed'>
  457.  { 1 index /Policies get 1 index
  458.     { type /integertype eq
  459.        { pop        % already processed
  460.        }
  461.        { 2 copy .knownget not { 1 index /PolicyNotFound get } if
  462.             % Stack: <orig> <merged> <failed> <Policies> <key>
  463.             %   <policy>
  464.      .policyprocs 1 index .knownget not { .policyprocs 0 get } if exec
  465.        }
  466.       ifelse
  467.     }
  468.    forall pop
  469.  } bind def
  470.  
  471. % Prepare to present parameters to the device, by spreading them onto the
  472. % operand stack and removing any that shouldn't be presented.
  473. /.prepareparams        % <params> .prepareparams -mark- <key1> <value1> ...
  474.  { mark exch dup
  475.     {            % Stack: -mark- key1 value1 ... merged key value
  476.       .presentspecial 2 index .knownget
  477.        { exec { 3 -1 roll } { pop pop } ifelse }
  478.        { 3 -1 roll }
  479.       ifelse
  480.     }
  481.    forall pop
  482.  } bind def
  483.  
  484. % Put device parameters without resetting currentpagedevice.
  485. % (.putdeviceparams clears the current page device.)
  486. /.putdeviceparamsonly    % <device> <Policies|null> <require_all> -mark-
  487.             %   <key1> <value1> ... .putdeviceparamsonly
  488.             % On success: <device> <eraseflag>
  489.             % On failure: <device> <Policies|null> <req_all> -mark-
  490.             %   <key1> <error1> ...
  491.  { .currentpagedevice
  492.     { counttomark 4 add 1 roll .putdeviceparams
  493.       dup type /booleantype eq { 3 } { counttomark 5 add } ifelse -1 roll
  494.       .setpagedevice
  495.     }
  496.     { pop .putdeviceparams
  497.     }
  498.    ifelse
  499.  } bind def
  500.  
  501. % Try setting the device parameters from the merged request.
  502. /.trysetparams        % <merged> <(ignored)> <device> <Policies>
  503.             %   .trysetparams
  504.  { true 4 index .prepareparams
  505.             % Add the computed .MediaSize.
  506.             % Stack: merged (ignored) device Policies -true-
  507.             %   -mark- key1 value1 ...
  508.    counttomark 5 add index .computemediasize
  509.    exch pop exch pop /.MediaSize exch
  510. DEBUG { (Putting.) = pstack flush } if
  511.    .putdeviceparamsonly
  512. DEBUG { (Result of putting.) = pstack flush } if
  513.  } bind def
  514.  
  515. % Compute the media size and initial matrix from a merged request (after
  516. % media selection).
  517. /.computemediasize    % <request> .computemediasize
  518.             %   <request> <matrix> <[width height]>
  519.  { dup /PageSize get                    % requested page size
  520.    1 index /InputAttributes get
  521.      2 index (%MediaSource) get get /PageSize get    % media size
  522.                             % (may be a range)
  523.    2 index /Policies get
  524.      dup /PageSize .knownget
  525.       { exch pop } { /PolicyNotFound get } ifelse    % PageSize policy,
  526.                             % affects scaling
  527.    3 index /Orientation .knownget not { null } if
  528.    4 index /RollFedMedia .knownget not { false } if
  529.    matrix .matchpagesize not {
  530.         % This is a "can't happen" condition!
  531.      /setpagedevice load /rangecheck signalerror
  532.    } if
  533.    2 array astore
  534.  } bind def
  535.  
  536. % ---------------- setpagedevice itself ---------------- %
  537.  
  538. /setpagedevice
  539.  {        % We mustn't pop the argument until the very end,
  540.         % so that the pseudo-operator machinery can restore the stack
  541.         % if an error occurs.
  542.    mark 1 index currentpagedevice
  543.  
  544.         % Check whether we are changing OutputDevice;
  545.         % also handle the case where the current device
  546.         % is not a page device.
  547.         % Stack: mark <request> <current>
  548. DEBUG { (Checking.) = pstack flush } if
  549.  
  550.    dup /OutputDevice .knownget
  551.     {        % Current device is a page device.
  552.       2 index /OutputDevice .knownget
  553.        {    % A specific OutputDevice was requested.
  554.      2 copy eq
  555.       { pop pop null }
  556.       { exch pop }
  557.      ifelse
  558.        }
  559.        { pop null
  560.        }
  561.       ifelse
  562.     }
  563.     {        % Current device is not a page device.
  564.         % Use the default device.
  565.       1 index /OutputDevice .knownget not { .defaultdevicename } if
  566.     }
  567.    ifelse
  568.    dup null eq
  569.     { pop
  570.     }
  571.     { exch pop .defaultdeviceparams
  572.         % In case of duplicate keys, .dicttomark takes the entry
  573.         % lower on the stack, so we can just append the defaults here.
  574.       .requiredattrs { exec } forall .dicttomark
  575.     }
  576.    ifelse
  577.  
  578.         % Check whether a viewer wants to intervene.
  579.         % We must check both the request (which takes precedence)
  580.         % and the current dictionary.
  581.         % Stack: mark <request> <orig>
  582.    exch dup /ViewerPreProcess .knownget
  583.     { exec }
  584.     { 1 index /ViewerPreProcess .knownget { exec } if }
  585.    ifelse exch
  586.  
  587.         % Construct a merged request from the actual request plus
  588.         % any keys that should always be propagated.
  589.         % Stack: mark <request> <orig>
  590. DEBUG { (Merging.) = pstack flush } if
  591.  
  592.    exch 1 index length 1 index length add dict
  593.    .copiedkeys
  594.     {        % Stack: <orig> <request> <merged> <key>
  595.       3 index 1 index .knownget { 3 copy put pop } if pop
  596.     }
  597.    forall
  598.         % Stack: <orig> <request> <merged>
  599.    dup 2 index
  600.     {        % stack: <orig> <request> <merged> <merged> <rkey> <rvalue>
  601.       .mergespecial 2 index .knownget { exec } if
  602.       put dup
  603.     }
  604.    forall pop
  605.         % Hack: if FIXEDRESOLUTION is true, discard any attempt to
  606.         % change HWResolution.
  607.    FIXEDRESOLUTION { dup /HWResolution .undef } if
  608.         % Hack: if FIXEDMEDIA is true, discard any attempt to change
  609.         % PageSize or HWSize.
  610.    FIXEDMEDIA
  611.     { dup /PageSize 4 index /PageSize get put
  612.       dup /HWSize 4 index /HWSize get put
  613.     } if
  614.         % Hack: to work around some files that take a PageSize
  615.         % from InputAttributes and impose it, discard any attempt
  616.         % to set PageSize to a 4-element value.
  617.         % Stack: mark <orig> <request> <merged>
  618.     dup /PageSize .knownget {
  619.       length 2 ne {
  620.     dup /PageSize 4 index /PageSize get put
  621.       } if
  622.     } if
  623.  
  624.         % Select input and output media.
  625.         % Stack: mark <orig> <request> <merged>
  626. DEBUG { (Selecting.) = pstack flush } if
  627.  
  628.    0 dict    % <failed>
  629.    1 index /InputAttributes .knownget
  630.     { 2 index /Policies get
  631.       .inputattrkeys (%MediaSource) cvn .selectmedia
  632.     } if
  633.    1 index /OutputAttributes .knownget
  634.     { 2 index /Policies get
  635.       .outputattrkeys (%MediaDestination) cvn .selectmedia
  636.      } if
  637.    3 -1 roll 4 1 roll        % temporarily swap orig & request
  638.    .applypolicies
  639.    3 -1 roll 4 1 roll        % swap back
  640.  
  641.         % Construct the new device, and attempt to set its attributes.
  642.         % Stack: mark <orig> <request> <merged> <failed>
  643. DEBUG { (Constructing.) = pstack flush } if
  644.  
  645.    currentdevice .devicename 2 index /OutputDevice get eq
  646.     { currentdevice }
  647.     { 1 index /OutputDevice get finddevice }
  648.    ifelse
  649.         %**************** We should copy the device here,
  650.         %**************** but since we can't close the old device,
  651.         %**************** we don't.  This is WRONG.
  652.     %****************copydevice
  653.    2 index /Policies get
  654.    .trysetparams
  655.    dup type /booleantype ne
  656.     {        % The request failed.
  657.         % Stack: ... <orig> <request> <merged> <failed> <device>
  658.         %   <Policies> true mark <name> <errorname> ...
  659. DEBUG { (Recovering.) = pstack flush } if
  660.       counttomark 4 add index
  661.       counttomark 2 idiv { dup 4 -2 roll put } repeat
  662.       pop pop pop
  663.         % Stack: mark ... <orig> <request> <merged> <failed> <device>
  664.         %   <Policies>
  665.       6 2 roll 3 -1 roll 4 1 roll
  666.       .applypolicies
  667.       3 -1 roll 4 1 roll 6 -2 roll
  668.       .trysetparams        % shouldn't fail!
  669.       dup type /booleantype ne
  670.        { 2 { counttomark 1 add 1 roll cleartomark } repeat
  671.          /setpagedevice load exch signalerror
  672.        }
  673.       if
  674.     }
  675.    if
  676.  
  677.         % The attempt succeeded.  Install the new device.
  678.         % Stack: mark ... <merged> <failed> <device> <eraseflag>
  679. DEBUG { (Installing.) = pstack flush } if
  680.  
  681.    pop 2 .endpage
  682.     { 1 true .outputpage
  683.       (>>setpagedevice, press <return> to continue<<\n) .confirm
  684.     }
  685.    if
  686.         % .setdevice clears the current page device!
  687.    .currentpagedevice pop exch
  688.    .setdevice pop
  689.    .setpagedevice
  690.  
  691.         % Merge the request into the current page device,
  692.         % unless we're changing the OutputDevice.
  693.         % Stack: mark ... <merged> <failed>
  694.    exch currentpagedevice dup length 2 index length add dict
  695.         % Stack: mark ... <failed> <merged> <current> <newdict>
  696.    2 index /OutputDevice .knownget {
  697.      2 index /OutputDevice .knownget not { null } if eq
  698.    } {
  699.      true
  700.    } ifelse {
  701.         % Same OutputDevice, merge the dictionaries.
  702.      .copydict
  703.    } {
  704.         % Different OutputDevice, discard the old dictionary.
  705.      exch pop
  706.    } ifelse .copydict
  707.         % Initialize the default matrix, taking media matching
  708.         % into account.
  709.    .computemediasize pop initmatrix concat
  710.    dup /PageOffset .knownget
  711.     {        % Translate by the given number of 1/72" units in device X/Y.
  712.       dup 0 get exch 1 get
  713.       2 index /HWResolution get dup 1 get exch 0 get
  714.       4 -1 roll mul 72 div   3 1 roll mul 72 div
  715.       idtransform translate
  716.     }
  717.    if
  718.         % We must install the new page device dictionary
  719.         % before calling the Install procedure.
  720.   dup .setpagedevice
  721.   .setdefaultscreen    % Set the default screen before calling Install.
  722.   dup /Install .knownget {
  723.     { .execinstall } stopped { .postinstall stop } { .postinstall } ifelse
  724.   } {
  725.     .postinstall
  726.   } ifelse
  727. } odef
  728.  
  729. % We break out the code after calling the Install procedure into a
  730. % separate procedure, since it is executed even if Install causes an error.
  731. % By making .execinstall a separate operator procedure, we get the stacks
  732. % restored if it fails.
  733.  
  734. /.execinstall {        % <proc> .execinstall -
  735.     % Because the interpreter optimizes tail calls, we can't just let
  736.     % the body of this procedure be 'exec', because that would lose
  737.     % the stack protection that is the whole reason for having the
  738.     % procedure in the first place.  We hack this by adding a couple
  739.     % of extra tokens to ensure that the operator procedure is still
  740.     % on the stack during the exec.
  741.   exec
  742.   0 pop    % See above.
  743. } odef
  744. /.postinstall {        % mark ... <failed> <merged> .postinstall -
  745.    matrix currentmatrix .setdefaultmatrix
  746.         % Erase and initialize the page.
  747.    erasepage initgraphics
  748.    .beginpage
  749.  
  750.         % Clean up, calling PolicyReport if needed.
  751.         % Stack: mark ... <failed> <merged>
  752. DEBUG { (Finishing.) = pstack flush } if
  753.  
  754.    exch dup length 0 ne
  755.     { 1 index /Policies get /PolicyReport get
  756.       counttomark 1 add 2 roll cleartomark
  757.       exec
  758.     }
  759.     { cleartomark
  760.     }
  761.    ifelse pop
  762.  
  763. } odef
  764.  
  765. end                % level2dict
  766. .setlanguagelevel
  767.